iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 25
1
Modern Web

新手也能懂的JS30系列 第 25

JS25-Event Capture, Propagation, Bubling & Once

  • 分享至 

  • xImage
  •  

Day25-課題內容

在今天的課題當中,我們要針對常用的 EventTarget.addEventListener 做進一步的認識。[1]

EventTarget.addEventListener

首先我們看到 MDN 中的定義:EventTarget.addEventListener() 方法,能將指定的事件監聽器註冊到 EventTarget 實作物件上。EventTarget 可能是 Document 中的 Element 物件、Document 物件本身、Window 物件,或是其它支援事件的物件。[2]
EventTarget.addEventListener() 的語法如下:

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);

參數

  1. type:監聽事件的名稱字串。
  2. listener:監聽事件發生時負責接收事件物件(Event 的實作物件)的物件,通常為函示。
  3. options:包含三種可選參數,可使 eventListener 含有特別的執行特性:
  • capture:將監聽事件的執行模式改為 capture phase。預設為 bubbling phase
  • once:選擇該監聽事件是否只監聽一次,如果為是監聽的事件將在觸發一次後就自動被移除。
  • passive:選擇這個屬性將無法在函式中使用 event.preventDefault() 方法。

option 參數的使用方法如下:

Event.target.addEventListener(type, function, {
    capture: ture/flase, 
    once:true/false,
    passive:true/false
});

Capture phase

我們已經知道 eventListener() 方法的預設模式為 bubbling phase 而不是 capture phase ,但是這兩者的差異在哪呢?
從參考網站以及 W3C 文件中,我們可以得知當一個事件被觸發的流程如下圖。[3][4]

當有一事件被觸發時,會先執行 capture phase ,然後才在我們指定的目標物件作動,最後執行 bubbling phase

  1. 當事件發生時,會先走 capture phase,也就是依序通知 Document -> <html> -> <body> -> <table> -> <tbody> -> <tr> 這些父元素容器 DOM 元件有事件被觸發。

  2. 然後到達目標物件之後通知 <td> 元素,事件被觸發了。

  3. 最後進行 bubbling phase,就是以相反的方向從 <td> 開始通知流程中的父元素容器 DOM 有事件發生。在通知完 Document 後,整個事件流程結束。

Event.stopPropagation()

由上方的事件流程圖我們得知事件觸發時系統判斷的過程,但是如果今天我們父元素容器們與子元素呈現重疊的狀態,且都包含監聽事件,如此一來我們按下目標子元素的話,整個 DOM 上的父元素都會被觸發事件。
為了要避免這種事情發生,我們可以在執行的函式中加入 event.stopPropagation() ,藉由加入此方法,當我們事件目標執行之後,就會停止後續 capture phasebubbling phase

總結

在今天的課題當中,我們將經常使用到的 EventTarget.addEventListener ,做更進一步的認識,
希望透過瞭解這些背後的機制,大家在使用時可以避開更多的地雷,以上是今天的內容,感謝您的閱讀。

參考資料

  1. javascript30
  2. EventTarget.addEventListener
  3. 介紹 DOM 及事件流程
  4. W3C-Document Object Model Events-Phases

上一篇
JS30-Day24-Sticky Nav
下一篇
JS30-Day26-Stripe Follow Along Nav
系列文
新手也能懂的JS3030
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言